<?php

namespace app\health\library\notice;

use app\health\library\notice\message\Link;
use app\health\library\notice\message\Markdown;
use app\health\library\notice\message\Message;
use app\health\library\notice\message\Text;
use GuzzleHttp\Client;
use think\Cache;

class DingTalk
{
    /**
     * @var string
     */
    public const REQUEST_URL_TEMPLATE = 'https://oapi.dingtalk.com/robot/send?access_token=%s&%s';

    protected $accesstoken;

    protected $secret;

    protected $message;

    /**
     * @var array
     */
    protected $mobiles = [];
    /**
     * @var bool
     */
    protected $atAll = false;


    protected $robot_name;

    public function __construct($default = '', $defaultConfig = [])
    {
        $config  = [];
        $default = $default ?: config('dingtalk_robot.default');
        if ($default) {
            $config = config('dingtalk_robot.config')[$default] ?? [];
        }
        if (!empty($defaultConfig)) {
            $config = $defaultConfig;
        }
        $this->robot_name = $config['robot_name'];
        $this->setAccessToken($config['token']);
        $this->setSecret($config['secret']);
    }

    /**
     * 设置钉钉机器人access_token
     * @param [type] $token
     * @Author 张旭鹏
     * @DateTime 2023-07-07
     */
    public function setAccessToken($token)
    {
        $this->accesstoken = $token;
        return $this;
    }

    public function setSecret($secret)
    {
        $this->secret = $secret;
        return $this;
    }

    protected function getRequestUrl(): string
    {
        $urlParams = '';
        if ($this->secret) {
            $urlParams = http_build_query([
                'timestamp' => $timestamp = time() . sprintf('%03d', random_int(1, 999)),
                'sign'      => $this->getSign($this->secret, $timestamp),
            ]);
        }

        return sprintf(static::REQUEST_URL_TEMPLATE, $this->accesstoken, $urlParams);
    }

    /**
     * 获取签名
     * @param string $secret
     * @param string $timestamp
     * @return string
     * @Author 张旭鹏
     * @DateTime 2023-07-07
     */
    protected function getSign(string $secret, string $timestamp): string
    {
        $data = sprintf("%s\n%s", $timestamp, $secret);

        $hash = hash_hmac('sha256', $data, $secret, true);

        return urlencode(base64_encode($hash));
    }

    public function at($mobiles = [], $atAll = false)
    {
        $this->mobiles = $mobiles;
        $this->atAll   = $atAll;
        return $this;
    }

    /**
     * 设置text文本消息
     * @param $content
     * @return $this
     */
    public function setTextMessage($content)
    {
        $this->message = new Text($content);
        return $this;
    }

    /**
     * @param $title
     * @param $text
     * @param $messageUrl
     * @param string $picUrl
     * @return $this
     */
    public function setLinkMessage($title, $text, $messageUrl, string $picUrl = ''): self
    {
        $this->message = new Link($title, $text, $messageUrl, $picUrl);
        return $this;
    }

    /**
     * @param $title
     * @param $markdown
     * @return $this
     */
    public function setMarkdownMessage($title, $markdown): self
    {
        $this->message = new Markdown($title, $markdown);
        return $this;
    }

    /**
     * 发送
     * @Author 张旭鹏
     * @DateTime 2023-07-07
     */
    public function send()
    {
        if (!($this->message instanceof Message) || empty($this->message->getBody())) {
            return ['errcode' => 40035, 'errmsg' => '请设置消息内容'];
        }
        $sendNum = Cache::get('dingtalk:' . $this->robot_name) ?: 0;
        if ($sendNum >= 20) { //发送到达每分钟最大20次阈值加入延迟队列发送
            queue('\app\health\job\SystemNoticeJob@delayMessage', ['dingtalk' => serialize($this)], mt_rand(20, 40), 'health');
            return true;
        }
        $this->message->sendAt($this->mobiles, $this->atAll);
        $body       = $this->message->getBody();
        $httpClient = new Client();
        $response   = $httpClient->post($this->getRequestUrl(), [
            'headers' => [
                'content-type' => 'application/json'
            ],
            'json'    => $body
        ]);
        $result     = json_decode($response->getBody()->getContents(), true);
        if ($result['errcode'] == 0) {
            if (Cache::has('dingtalk:' . $this->robot_name)) {
                Cache::inc('dingtalk:' . $this->robot_name);
            } else {
                Cache::set('dingtalk:' . $this->robot_name, 1, 60);
            }
            return true;
        }
        return $result;
    }
}
